package com.liaoyifan.core.converter.handler;

import static com.liaoyifan.core.converter.annotation.DateTimeConversion.*;

import com.liaoyifan.core.constant.Constants;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@SuppressWarnings("unused")
public class DateTimeHandler {

    private static final Map<String, DateTimeFormatter> FORMATTER_CACHE = new ConcurrentHashMap<>();

    @ToEpochMillis
    public static Long toEpochMillis(LocalDateTime dateTime) {
        return dateTime != null
                ? dateTime.atZone(Constants.UTC_ZONE).toInstant().toEpochMilli()
                : null;
    }

    @FromEpochMillis
    public static LocalDateTime fromEpochMillis(Long epochMillis) {
        return epochMillis != null
                ? Instant.ofEpochMilli(epochMillis).atZone(Constants.UTC_ZONE).toLocalDateTime()
                : null;
    }

    @FromLocalDateTime
    public static String fromLocalDateTime(LocalDateTime dateTime) {
        return dateTime != null ? dateTime.format(getDateTimeFormatter()) : null;
    }

    @FromLocalDate
    public static String fromLocalDate(LocalDate date) {
        return date != null ? date.format(getDateFormatter()) : null;
    }

    @ToLocalDateTime
    public static LocalDateTime toLocalDateTime(String dateTimeStr) {
        return dateTimeStr != null
                ? LocalDateTime.parse(dateTimeStr, getDateTimeFormatter())
                : null;
    }

    @ToLocalDate
    public static LocalDate toLocalDate(String dateStr) {
        return dateStr != null ? LocalDate.parse(dateStr, getDateFormatter()) : null;
    }

    @FromDate
    public static String fromDate(Date date) {
        if (date == null) {
            return null;
        }
        LocalDate localDate = date.toInstant().atZone(Constants.UTC_ZONE).toLocalDate();
        return localDate.format(getDateFormatter());
    }

    @FromDateTime
    public static String fromDateTime(Date date) {
        if (date == null) {
            return null;
        }
        LocalDateTime localDateTime = date.toInstant().atZone(Constants.UTC_ZONE).toLocalDateTime();
        return localDateTime.format(getDateTimeFormatter());
    }

    @ToDate
    public static Date toDate(String dateStr) {
        if (dateStr == null) {
            return null;
        }
        LocalDate localDate = LocalDate.parse(dateStr, getDateFormatter());
        Instant instant = localDate.atStartOfDay(Constants.UTC_ZONE).toInstant();
        return Date.from(instant);
    }

    @ToDateTime
    public static Date toDateTime(String dateTimeStr) {
        if (dateTimeStr == null) {
            return null;
        }
        LocalDateTime localDateTime = LocalDateTime.parse(dateTimeStr, getDateTimeFormatter());
        Instant instant = localDateTime.atZone(Constants.UTC_ZONE).toInstant();
        return Date.from(instant);
    }

    public static DateTimeFormatter getDateFormatter() {
        return getFormatter(Constants.DATE_PATTERN);
    }

    public static DateTimeFormatter getDateTimeFormatter() {
        return getFormatter(Constants.DATETIME_PATTERN);
    }

    public static DateTimeFormatter getFormatter(String pattern) {
        return FORMATTER_CACHE.computeIfAbsent(pattern, DateTimeFormatter::ofPattern);
    }
}
